package cn.xhh.dailyreview.client;

import cn.xhh.dailyreview.client.utils.ClientUtil;
import cn.xhh.dailyreview.client.utils.MsgCallback;
import cn.xhh.dailyreview.client.utils.Result;
import cn.xhh.dailyreview.client.utils.Token;

import com.extjs.gxt.ui.client.Style.LayoutRegion;
import com.extjs.gxt.ui.client.core.FastMap;
import com.extjs.gxt.ui.client.util.Margins;
import com.extjs.gxt.ui.client.widget.Html;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.Text;
import com.extjs.gxt.ui.client.widget.Viewport;
import com.extjs.gxt.ui.client.widget.layout.BorderLayout;
import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;
import com.extjs.gxt.ui.client.widget.layout.HBoxLayout;
import com.extjs.gxt.ui.client.widget.layout.VBoxLayout;
import com.extjs.gxt.ui.client.widget.layout.VBoxLayoutData;
import com.extjs.gxt.ui.client.widget.layout.BoxLayout.BoxLayoutPack;
import com.extjs.gxt.ui.client.widget.layout.HBoxLayout.HBoxLayoutAlign;
import com.extjs.gxt.ui.client.widget.layout.VBoxLayout.VBoxLayoutAlign;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * The entry point defining <code>onModuleLoad()</code>.
 */
public class DailyReview implements EntryPoint {
	
	public static final DailyReviewConstants constants = 
		GWT.create(DailyReviewConstants.class);
	
	private final Viewport main;
	private final Text info;
	private final LayoutContainer options;
	private final Html poweredBy;

	private LoginPanel login;
	private OverviewPanel overview;
	
	private String email;
	private int userLevel = -1;

	public DailyReview() {
		main = new Viewport();
		VBoxLayout layout = new VBoxLayout();
		main.setLayout(layout);
		layout.setVBoxLayoutAlign(VBoxLayoutAlign.CENTER);
		
		info = new Text("");
		info.setHeight(15);
		
		options = new LayoutContainer();
		HBoxLayout optLayout = new HBoxLayout();
		optLayout.setHBoxLayoutAlign(HBoxLayoutAlign.MIDDLE);
		optLayout.setPack(BoxLayoutPack.END);
		options.setLayout(optLayout);
		options.setWidth("90%");
		options.setHeight(15);
		
		poweredBy = new Html("<a href=\"http://daily-review.googlecode.com\"" +
				" target=\"_blank\">Project Details</a>");
		poweredBy.addStyleName("login-options");
	}

	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {
		LayoutContainer all = new LayoutContainer();
		BorderLayout layout = new BorderLayout();
		all.setLayout(layout);
		
		main.add(info, new VBoxLayoutData(5, 0, 0, 0));
		BorderLayoutData ld = new BorderLayoutData(LayoutRegion.CENTER);
		all.add(main, ld);
		
		ld = new BorderLayoutData(LayoutRegion.SOUTH, 30f);
		ld.setMargins(new Margins(0, 0, 5, 0));
		all.add(poweredBy, ld);
		
		RootPanel rootPanel = RootPanel.get();
		rootPanel.add(all);
		
		final MsgCallback acCheckLogin = new MsgCallback(this) {
			public void onSuccess(Result result) {
				hideInfo();
				if (result.successful()) {
					setEmail(result.getValue("email"));
					try {
						setUserLevel(Integer.parseInt(result.getValue("userLevel")));
					} catch (NumberFormatException e) {
						GWT.log("Parsing user level failed! " + result.getValue("userLevel"), e);
						ClientUtil.alert("Loading your information failed!");
					}
					showOverview();
				} else showLogin();
			}
		};
		
		History.addValueChangeHandler(new ValueChangeHandler<String>() {
			@Override
			public void onValueChange(ValueChangeEvent<String> event) {
				String token = event.getValue();
				if (ClientUtil.isBlank(token))
					return;
				
				FastMap<String> params = ClientUtil.parseToken(token);
				String action = params.get(Token.action.toString());
				// confirm registration or reset password
				if (Token.confirm.same(action) || Token.reset_pwd.same(action)) {
					String email = params.get(Token.email.toString());
					String code = params.get(Token.code.toString());
					if (email == null) email = "";
					showLogin(Token.valueOf(action), email, code);
				} else {
					showLoading();
					ClientUtil.getService().checkLogin(acCheckLogin);
				}
			}
		});
		
		String token = History.getToken();
		if (ClientUtil.notBlank(token))
			History.fireCurrentHistoryState();
		else {
			showLoading();
			ClientUtil.getService().checkLogin(acCheckLogin);
		}
	}

	/**
	 * Show the main panel, with the options panel at the top and the body panel "p" below it.
	 * @param p the body panel
	 * @param optMargin the margin between the options panel and the body panel
	 * @see DailyReview#getOptions()
	 */
	void showPanel(Widget p, int optMargin) {
		main.removeAll();
		main.add(info, new VBoxLayoutData(5, 0, 0, 0));
		main.add(options, new VBoxLayoutData(0, 0, optMargin, 0));
		main.add(p);
		main.layout();
	}
	

	/**
	 * Show panel with the default optMargin: 20. See {@link DailyReview#showPanel(Widget, int)}
	 */
	void showPanel(Widget p) {
		showPanel(p, 20);
	}
	
	public void showLogin() {
		if (login == null)
			login = new LoginPanel(this);
		login.show(null, null, null);
	}
	
	public void showLogin(Token token, String email, String code) {
		if (login == null)
			login = new LoginPanel(this);
		login.show(token, email, code);
	}

	public void showOverview() {
//		showPanel(new ReviewPanel(this, Arrays.asList("A", "B", "C"), null)); // XXX
		if (overview == null)
			overview = new OverviewPanel(this);
		overview.show();
	}

	public Viewport getMain() {
		return main;
	}

	/**
	 * @return the options panel, displaying some options links with right alignment
	 */
	public LayoutContainer getOptions() {
		return options;
	}
	
	/**
	 * @return the info panel for telling the user the current operation or result, e.g. "Loading..."
	 */
	public Text getInfo() {
		return info;
	}

	/**
	 * Display a message with the info panel for the uesr's information
	 * @param msg the message to display
	 */
	public void showInfo(String msg) {
		info.setText(msg);
		info.addStyleName("info");
	}
	
	public void hideInfo() {
		info.setText("");
		info.removeStyleName("info");
	}

	/**
	 * Show a "Loading..." (i18n) message in the info panel.
	 * @see #showInfo(String)
	 */
	public void showLoading() {
		showInfo(constants.loading());
	}

	public String getEmail() {
		return email;
	}
	
	public void setEmail(String email) {
		this.email = email;
	}

	public void setUserLevel(int userLevel) {
		this.userLevel = userLevel;
	}

	public int getUserLevel() {
		return userLevel;
	}

}
